/**
 * Created by zhangguangde on 2019/1/8.
 */

// 插件引入
var fs = require('fs');
var readLine = require('lei-stream').readLine;
var Array = require('node-array');
var mysql = require('mysql');
var moment = require('moment');
var path = require('path');


// 数据库连接
var connection = mysql.createConnection({
    host : '127.0.0.1',
    port : 3306,
    user : 'root',
    password : 'root',
    database : 'statistical',
    charset : 'UTF8_GENERAL_CI',
    debug : false
});

// 表名
var tableName = "main";

// 输出错误sql文log
// 文件名与当前日期相同
var outputSuccessSql = './sqlerror/' + moment().format('YYYY_MM_DD_HH_mm_ss');
var outputErrorSql = fs.createWriteStream(outputSuccessSql);

// 用来存储数据
var dataList = [];
// 文件集合
var logFiles = [];
// 获取参数
var arguments = process.argv;
//解析需要遍历的文件夹 调用文件遍历方法(最多耗时1000ms)
fileDisplay(arguments[2]);

// 由于度文件名目前无法解决回调问题，只能做延迟任务
// 进行读文件操作
setTimeout(function() {
    console.log('-------------');
    // 打印文件list
    console.log('文件名列表', logFiles);
    console.log('处理开始');
    console.log('-------------');
    // 读文件
    readFiles(logFiles);    
}, 1000);
return false;


/*
    同步foreach循环
    可传入多个文件
    循环处理
*/
function readFiles(files) {
    // 同步foreach循环
    // 可传入多个文件
    // 循环处理
    files.forEachAsync(function(file, index, arr, readFileNext) {
        console.log('处理文件', file);

        // 打印开始读文件的时间
        console.log('read start: ', new Date());

        // 成功条数计数器
        var i = 0;
        // 失败条数计数器
        var j = 0;

        // 写入错误输出文件
        // 命名与所读文件名称相同
        var outputErrorFile = './error/' + file.replace(/\\/g,"_");
        var outputError = fs.createWriteStream(outputErrorFile);
        // 写入成功输出文件
        // 命名与所读文件名称相同
        var outputSuccessFile = './success/' + file.replace(/\\/g,"_");
        var outputSuccess = fs.createWriteStream(outputSuccessFile);

        // 读文件
        readLine(file).go(function (data, readLineNext) {

            try {
                i++;

                var json = JSON.parse(data);

                // 判断是否存在‘currentPage’关键字
                // 纯在的场合 代表有效pv访问
                if (json.url && addQueryFlag(json.url)) {
                    // 加入对象
                    dataList.push(json)
                    // 写成功文件
                    outputSuccess.write(i + ':\n' + data + '\n');
                }
            }
            catch(e){
                // 异常的场合，失败计数器自增，写入error
                j++;
                outputError.write(j + ':\n' + data + '\n');
            }

            readLineNext();
        }, function () {
            console.log('read end: ', new Date());
            console.log('read line : ', i);
            console.log('read catch', j);

            console.log('-------------');
            readFileNext();
        });

        return true;
    }, function() {
        // 处理完成 回调函数
        console.log('处理完成');
        console.log("数据条数: ", dataList.length);

        console.log('-------------');
        console.log("存储开始");

        // 从第0条开始存储，每次存储2000条
        saveMysql(0, 200);

    });

}

/*
    截取url中的参数
*/
function getQueryString(url, name) {
    // name == currentPage 的场合
    // 特殊处理
    if (name == 'currentPage') {
        if (url.indexOf('currentPage') != -1) {
            // 存在 currentPage 的场合
            var currentPageStr = url.substr(url.indexOf('currentPage') + 12);
            return currentPageStr.substr(0, currentPageStr.indexOf(' '))
        } else {
            // 不存在的场合，返回 空
            return null;
        }
    } else {
        // 普通的场合    
        var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
        var r = url.substr(1).match(reg);
        if (r != null) {
            return unescape(r[2]);
        }
        return null;
    }
}

/*
    判断是否加入 sql文 进行存表
*/
function addQueryFlag(value) {
    if (value.indexOf('userId') != -1 && value.indexOf('currentPage') != -1) {
        return true;
    } else {
        return false;
    }
}

/*
    生成sql文
    index条开始，
    存num条
*/
function editQuery(dataList, index, num) {
    var query = '';
    for (var i = index; i < index + num; i++) {

        // 正常场合，进行sql文拼接
        // 边界值的场合，跳出循环
        if (dataList[i]) {

            // 两种场合，query没有被编辑过，的时候写入第一条数据格式，被编辑过的场合，写入非第一条数据格式
            if (!query) {
                query = "INSERT INTO `" + tableName + "` (`time`,`ip`, `url`, `user_id`, `ua`) VALUES (\"" + dataList[i].time + "\", \"" + dataList[i].ip + "\", \"" + getQueryString(dataList[i].url, 'currentPage') + "\", \"" + getQueryString(dataList[i].url, 'userId') + "\", \"" + dataList[i].ua + "\"" + ")\n";
            } else {
                // 编辑 sql 文后续进行存表用
                query += ", (\"" + dataList[i].time + "\", \"" + dataList[i].ip + "\", \"" + getQueryString(dataList[i].url, 'currentPage') + "\", \"" + getQueryString(dataList[i].url, 'userId') + "\", \"" + dataList[i].ua + "\"" + ")\n";
            }

        } else {
            // 边界值的场合，跳出循环
            break;
        }
    }
    return query;
}

/*
* 存储数据库，
* index条开始，
* 存num条
* */
function saveMysql(index, num) {

    // 生成sql文
    var query = editQuery(dataList, index, num)

    // SQL文正常生成的场合
    if (query) {

        try {
            // 存储数据库
            connection.query(query, function(err, result) {
                if (err) {
                    console.log("存储失败：", index + '---' + (index + num) );
                    // 写错误log
                    outputErrorSql.write(index + '~' + (index + num) + ':\n' + query + '\n');
                    // 抛出异常，并且终止程序
                    // throw err;
                } else {
                    console.log("存储成功：", index + '---' + (index + num) );
                }
                if (index + num < dataList.length) {
                    saveMysql(index + num, num);
                } else {
                    // 关闭数据库连接
                    connection.end();
                    console.log('-------------');
                }
            });
        } catch(e){
            console(e)

        }

    }
}

/**
 * 文件遍历方法
 * @param filePath 需要遍历的文件路径
 */
function fileDisplay(filePath) {
    //根据文件路径读取文件，返回文件列表
    fs.readdir(filePath, function(err, files) {
        if(err) {
            console.warn(err)
        } else {
            //遍历读取到的文件列表
            files.forEach(function(filename) {
                //获取当前文件的绝对路径
                var filedir = path.join(filePath,filename);
                //根据文件路径获取文件信息，返回一个fs.Stats对象
                fs.stat(filedir, function(eror, stats) {
                    if(eror) {
                        console.warn('获取文件stats失败');
                    } else {
                        var isFile = stats.isFile();//是文件
                        var isDir = stats.isDirectory();//是文件夹
                        if(isFile) {
                            logFiles.push(filedir);
                        }
                        if(isDir) {
                            fileDisplay(filedir);//递归，如果是文件夹，就继续遍历该文件夹下面的文件
                        }
                    }
                })
            });
        }
    });

}